/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef _OSI_PARSE_UTILS_H_
#define _OSI_PARSE_UTILS_H_

#include <unistd.h>  // 提供 access() 函数和 F_OK/R_OK 常量定义
#include "nfc_osi_api.h"
#include "nfc_types.h"

#define CF_PARSE_HEX_BASE 16
#define CF_HEX_PREFIX_OFFSET 2

static inline uint16_t nfc_cf_get_err_sum(uint32_t result)
{
    return (uint16_t)(result & 0xFFFF);
}

static inline uint16_t nfc_cf_get_err_line(uint32_t result)
{
    return (uint16_t)((result >> CF_PARSE_HEX_BASE) & 0xFFFF);
}

static inline uint32_t nfc_cf_set_status(uint16_t line_num, uint16_t err_sum)
{
    return ((line_num << CF_PARSE_HEX_BASE) | err_sum);
}

/**
 * @brief 内部辅助宏：接收至少两个参数，返回第二个参数。
 *        用于提取由 GET_FIRST_ARG_OR_DEFAULT 构造的参数列表中的目标值。
 */
#define GET_FIRST_ARG_HELPER(DEFAULT_VALUE_IGNORED, FIRST_ARG_OR_DEFAULT, ...) FIRST_ARG_OR_DEFAULT

/**
 * @brief 内部辅助宏：如果 __VA_ARGS__ 为空，则返回 DEFAULT；
 *        如果 __VA_ARGS__ 非空，则返回 __VA_ARGS__ 中的第一个参数。
 *        利用 ##__VA_ARGS__ 的 GNU 扩展来调整传递给 GET_FIRST_ARG_HELPER 的参数。
 */
#define GET_FIRST_ARG_OR_DEFAULT(DEFAULT, ...) \
    GET_FIRST_ARG_HELPER(DEFAULT, ##__VA_ARGS__, DEFAULT)

/**
 * @brief 定义键值对映射关系
 */
#define ITEM(k, v, t, d) \
    { .key = (k), .p_##t = (v), .type = (t), .d_##t = (d), .present = false }

/**
 * @brief 定义布尔类型的键值对
 */
#define BOOL_ITEM(key, p_value, ...) ITEM(key, p_value, BOOL_TYPE, GET_FIRST_ARG_OR_DEFAULT(false, ##__VA_ARGS__))

/**
 * @brief 定义8位无符号整数类型的键值对
 */
#define UINT8_ITEM(key, p_value, ...) ITEM(key, p_value, UINT8_TYPE, GET_FIRST_ARG_OR_DEFAULT(0, ##__VA_ARGS__))

/**
 * @brief 定义16位无符号整数类型的键值对
 */
#define UINT16_ITEM(key, p_value, ...) ITEM(key, p_value, UINT16_TYPE, GET_FIRST_ARG_OR_DEFAULT(0, ##__VA_ARGS__))

/**
 * @brief 定义32位无符号整数类型的键值对
 */
#define UINT32_ITEM(key, p_value, ...) ITEM(key, p_value, UINT32_TYPE, GET_FIRST_ARG_OR_DEFAULT(0, ##__VA_ARGS__))

/**
 * @brief 定义字符串类型的键值对
 */
#define STRING_ITEM(key, p_value, ...) ITEM(key, p_value, STRING_TYPE, GET_FIRST_ARG_OR_DEFAULT(NULL, ##__VA_ARGS__))

/**
 * @brief 定义数组类型的键值对
 */
#define ARRAY_ITEM(key, p_value, ...) ITEM(key, p_value, ARRAY_TYPE, GET_FIRST_ARG_OR_DEFAULT(NULL, ##__VA_ARGS__))

/**
 * @brief 支持的配置项类型
 */
typedef enum {
    BOOL_TYPE,
    UINT8_TYPE,
    UINT16_TYPE,
    UINT32_TYPE,
    STRING_TYPE,
    ARRAY_TYPE,
} tNFC_CF_KEY_TYPE;

/**
 * @brief 键值对列表存储类型
 */
typedef struct {
    const char       *key;
    union {
        bool          *p_BOOL_TYPE;
        uint8_t       *p_UINT8_TYPE;
        uint16_t      *p_UINT16_TYPE;
        uint32_t      *p_UINT32_TYPE;
        char          **p_STRING_TYPE;
        tNFC_CF_ARRAY *p_ARRAY_TYPE;
    };
    union {
        const bool     d_BOOL_TYPE;
        const uint8_t  d_UINT8_TYPE;
        const uint16_t d_UINT16_TYPE;
        const uint32_t d_UINT32_TYPE;
        const char     *d_STRING_TYPE;
        const char     *d_ARRAY_TYPE;
    };
    tNFC_CF_KEY_TYPE type;
    bool             present;
} tNFC_CF_PARAM;

#ifdef __cplusplus
extern "C" {
#endif
/**
 * @brief 在指定目录列表中查找第一个存在且可读的文件
 *
 * @param dirs 目录路径字符串数组
 * @param num 目录路径数组中的元素数量
 * @return 如果找到文件，则返回指向该文件路径的指针；否则返回 NULL
 */
static inline const char* osi_config_file_find(const char* dirs[], size_t num)
{
    for (size_t i = 0; i < num; i++) {
        if (access(dirs[i], F_OK | R_OK) == 0) {
            return dirs[i];
        }
    }
    NFCLOG_E("Failed to find config file");
    return NULL;
}

/**
 * @brief 解析配置项的字符串值
 *
 * 根据配置项的类型，将字符串值解析为相应的数据类型，并存储到配置项结构体中。
 *
 * @param[in] p_value 字符串值
 * @param[in] item 配置项结构体指针
 *
 * @return 解析成功返回 true，失败返回 false。
 */
bool osi_config_parse_item(char *p_value, tNFC_CF_PARAM *item);
/**
 * @brief 解析配置项的默认值
 *
 * 遍历配置项列表，将配置项设置为默认值。
 *
 * @param lists     配置项参数列表的指针。
 * @param list_num  配置项参数列表中元素的数量。
 *
 * @return          解析成功返回true，失败返回false。
 */
bool osi_config_set_defaults(tNFC_CF_PARAM *lists, size_t list_num);
/**
 * @brief 解析指定路径的conf配置文件
 *
 * 从给定的文件路径读取conf配置文件，并解析其中的配置项。
 * 对于每一行配置，解析键值对，并根据配置项类型进行解析。
 * 支持跨行配置，使用{}包围跨行值。
 *
 * @param path_name 配置文件的路径
 * @param lists 配置项列表
 * @param list_num 配置项数量
 *
 * @return 解析结果状态码，包含解析的行数和错误数量。
 *         解析成功返回错误项为0，并一起返回解析行数。
 */
uint32_t osi_config_parse(const char *path_name, tNFC_CF_PARAM *lists, size_t list_num);
/**
 * @brief 释放配置参数列表中的动态分配内存
 *
 * 此函数主要完成以下操作：
 * 1. 释放配置参数列表中动态分配的内存，包括数组类型和字符串类型的配置项。
 * 2. 将相关指针置为NULL，并重置present标志，防止悬空指针或脏数据。
 *
 * @param lists     配置参数列表指针，包含需要释放内存的配置项
 * @param list_num  配置参数列表中的配置项数量
 */
void osi_config_unparse(tNFC_CF_PARAM *lists, size_t list_num);
/**
 * @brief 检查指定的键值是否存在于配置中，并返回对应的值
 *
 * @param[in] lists 配置参数列表
 * @param[in] list_num 配置参数列表的长度
 * @param[in] key 配置项的键，用于在配置列表中查找对应的配置项
 * @param[out] pp_value 返回指向键对应配置项值的指针
 * @param[out] value_size 返回键对应配置项值大小的指针
 *
 * @return 如果成功找到配置项并复制其值的指针，返回true；否则返回false
 */
bool osi_config_get_value_present(tNFC_CF_PARAM *lists, size_t list_num,
                                  const char *key, const void **pp_value, size_t *value_size);
#ifdef __cplusplus
};
#endif

#endif /* _OSI_PARSE_UTILS_H_ */